package com.wmx.thymeleafapp.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;

/**
 * Java jdk 原生 Aes 加解密
 * Advanced Encrytion Standard（高级加密标准），特点：1. 对称加密  2. 一个 SECRET_KEY（密钥）扩展成多个子 SK，轮加密
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2024/4/13 10:16
 */
public class AesUtil {

    private static final String ALGORITHM_AES = "AES";
    // keySize must be equal to 128, 192 or 256
    private static final int KEY_SIZE = 256;
    private static final String CHARSET_UTF8 = "utf-8";

    private static final Logger log = LoggerFactory.getLogger(AesUtil.class);

    /**
     * 生成密钥文本 - 保存记录起来（在配置文件、或者数据库中），用于后续进行加解密使用。
     *
     * @param keySrc ：用于生成密钥的内容，可以任意随机
     * @return ：返回密钥文本，如 SMtnONQhBBRiDWRS4GHn0z7mX9DFMl3LWexekXf9pRo=
     * @throws Exception
     */
    public static String generateKey(String keySrc) throws Exception {
        if (keySrc == null || keySrc.trim().isEmpty()) {
            keySrc = System.currentTimeMillis() + UUID.randomUUID().toString();
        }
        KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM_AES);
        SecureRandom random = new SecureRandom(keySrc.getBytes(CHARSET_UTF8));
        keyGen.init(KEY_SIZE, random);
        SecretKey secretKey = keyGen.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * AES 加密
     *
     * @param content       ：被加密的内容文本
     * @param secretKeyText ：密钥文本
     * @return ：加密后的内容(base64)
     * @throws Exception
     */
    public static String encrypt(String content, String secretKeyText) throws Exception {
        if (content == null || content.isEmpty() || secretKeyText == null || secretKeyText.trim().isEmpty()) {
            return null;
        }
        SecretKey secretKey = strKeyToSecretKey(secretKeyText);
        byte[] contentBytes = content.getBytes(CHARSET_UTF8);
        byte[] encryptBytes = encryptAES(contentBytes, secretKey);
        return Base64.getEncoder().encodeToString(encryptBytes);
    }

    /**
     * AES 解密
     *
     * @param cipherText    ：密文(base64)
     * @param secretKeyText ：密钥
     * @return ：解密好的内容
     * @throws Exception
     */
    public static String decrypt(String cipherText, String secretKeyText) throws Exception {
        if (cipherText == null || cipherText.trim().isEmpty() || secretKeyText == null || secretKeyText.trim().isEmpty()) {
            return null;
        }
        SecretKey secretKey = strKeyToSecretKey(secretKeyText);
        byte[] decode = Base64.getDecoder().decode(cipherText);
        byte[] decryptBytes = decryptAES(decode, secretKey);
        return new String(decryptBytes, CHARSET_UTF8);
    }

    /**
     * 生成密钥对象 - 用于根据密钥文本创建密钥对象进行数据加解密。
     *
     * @param strKey ：密钥文本
     * @return ：密钥对象
     */
    private static SecretKey strKeyToSecretKey(String strKey) {
        byte[] bytes = Base64.getDecoder().decode(strKey);
        SecretKeySpec secretKey = new SecretKeySpec(bytes, ALGORITHM_AES);
        return secretKey;
    }

    /**
     * AES 加密
     *
     * @param content   ：被解密的内容
     * @param secretKey ：密钥对象
     * @return ：解密内容
     * @throws Exception
     */
    private static byte[] encryptAES(byte[] content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_AES);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(content);
    }

    /**
     * AES 解密
     *
     * @param content   ：被加密的内容
     * @param secretKey ：密钥
     * @return ：加密好的内容
     * @throws Exception
     */
    private static byte[] decryptAES(byte[] content, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM_AES);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(content);
    }

    public static void main(String[] args) throws Exception {
        String data = "AES: Advanced Encrytion Standard（高级加密标准），特点：1. 对称加密  2. 一个 SECRET_KEY（密钥）扩展成多个子 SK，轮加密";
        String keySrc = "e27568c9-658c-49ea-b178-1437fce69046";

        String secretKeyText = AesUtil.generateKey(keySrc);
        // 密钥文本-> SMtnONQhBBRiDWRS4GHn0z7mX9DFMl3LWexekXf9pRo=
        System.err.println("密钥文本-> " + secretKeyText);

        String cipherText = AesUtil.encrypt(data, secretKeyText);
        // 密文-> 1IcOOi55CzrYnKZq1pD10r4Rl26ltgJ95uQ0HMh56V7EL5I8eRLnj8s6lZvxcVMPc8XrfDHZB/298t3J05WWlAsplKawAjaaf+7SMaAewV2EAb+jC05oc9Xk02VXzp395SGQVHL+3scSlhMkvXxtEwX9n7hrXs24wCTScAiFjxkQmQkKqSkQQ4Hn2SWvoD57HJsxO0ZLxbWWfxm6RJTLSw==
        System.out.println("密文-> " + cipherText);

        String deStr = AesUtil.decrypt(cipherText, secretKeyText);
        System.out.println("明文-> " + deStr);
    }

}